<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.1">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/%E6%AD%A6%E6%B1%8932x32.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/%E6%AD%A6%E6%B1%8916x16.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib1/font-awesome/css/all.min.css">
  <link rel="stylesheet" href="/lib1/pace/pace-theme-center-simple.min.css">
  <script src="/lib1/pace/pace.min.js"></script>

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"example.com","root":"/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="基础架构1、数组与函数的关系数组与函数并无本质区别，均是一种映射的形式。变量函数，指针数组。 数组：展开的函数，关键在于指针变化，查询时间快。 函数：压缩的数组，关键在于值传递，用INDEX来定位，所用空间小。 算法中的时空互换逻辑，时间复杂度与空间复杂度可以一定程度互换。 2、C++的编程逻辑面向过程：自顶向下的编程，性能高，但需要处理实现性能的每一个细节，难以复用、扩展。 面向对象：抽象化事物">
<meta property="og:type" content="article">
<meta property="og:title" content="C++初见">
<meta property="og:url" content="http://example.com/2020/08/19/C++/C-%E5%9B%9B%E5%A4%A9%E5%85%A5%E9%97%A8/index.html">
<meta property="og:site_name" content="Technological Blog">
<meta property="og:description" content="基础架构1、数组与函数的关系数组与函数并无本质区别，均是一种映射的形式。变量函数，指针数组。 数组：展开的函数，关键在于指针变化，查询时间快。 函数：压缩的数组，关键在于值传递，用INDEX来定位，所用空间小。 算法中的时空互换逻辑，时间复杂度与空间复杂度可以一定程度互换。 2、C++的编程逻辑面向过程：自顶向下的编程，性能高，但需要处理实现性能的每一个细节，难以复用、扩展。 面向对象：抽象化事物">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://www.runoob.com/wp-content/uploads/2014/09/v2-749cc641eb4d5dafd085e8c23f8826aa_hd.png">
<meta property="og:image" content="https://www.runoob.com/wp-content/uploads/2014/09/v2-48240f0e1e0dd33ec89100cbe2d30707_hd.png">
<meta property="article:published_time" content="2020-08-19T10:14:31.000Z">
<meta property="article:modified_time" content="2021-11-03T08:18:02.976Z">
<meta property="article:author" content="Li Yudong">
<meta property="article:tag" content="C++初学">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://www.runoob.com/wp-content/uploads/2014/09/v2-749cc641eb4d5dafd085e8c23f8826aa_hd.png">

<link rel="canonical" href="http://example.com/2020/08/19/C++/C-%E5%9B%9B%E5%A4%A9%E5%85%A5%E9%97%A8/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>C++初见 | Technological Blog</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">Technological Blog</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">IT小白的成长之旅</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-about">

    <a href="/about/" rel="section"><i class="user fa-fw"></i>关于</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="tags fa-fw"></i>标签<span class="badge">18</span></a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="th fa-fw"></i>分类<span class="badge">14</span></a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="archive fa-fw"></i>归档<span class="badge">95</span></a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>

  <a href="https://github.com/tiarmor1" class="github-corner" title="Follow me on GitHub" aria-label="Follow me on GitHub" rel="noopener" target="_blank"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://example.com/2020/08/19/C++/C-%E5%9B%9B%E5%A4%A9%E5%85%A5%E9%97%A8/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/author.jpg">
      <meta itemprop="name" content="Li Yudong">
      <meta itemprop="description" content="">
    </span>
    
    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Technological Blog">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          C++初见
        </h1>
    
        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
    
              <time title="创建时间：2020-08-19 18:14:31" itemprop="dateCreated datePublished" datetime="2020-08-19T18:14:31+08:00">2020-08-19</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2021-11-03 16:18:02" itemprop="dateModified" datetime="2021-11-03T16:18:02+08:00">2021-11-03</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/C/" itemprop="url" rel="index"><span itemprop="name">C++</span></a>
                </span>
            </span>
    
          
    
        </div>
      </header>
    
    
    
    
    <div class="post-body" itemprop="articleBody">
    
      
        <h1 id="基础架构"><a href="#基础架构" class="headerlink" title="基础架构"></a>基础架构</h1><h2 id="1、数组与函数的关系"><a href="#1、数组与函数的关系" class="headerlink" title="1、数组与函数的关系"></a>1、数组与函数的关系</h2><p>数组与函数并无本质区别，均是一种映射的形式。变量函数，指针数组。</p>
<p>数组：展开的函数，关键在于指针变化，查询时间快。</p>
<p>函数：压缩的数组，关键在于值传递，用INDEX来定位，所用空间小。</p>
<p>算法中的时空互换逻辑，时间复杂度与空间复杂度可以一定程度互换。</p>
<h2 id="2、C-的编程逻辑"><a href="#2、C-的编程逻辑" class="headerlink" title="2、C++的编程逻辑"></a>2、C++的编程逻辑</h2><p>面向过程：自顶向下的编程，性能高，但需要处理实现性能的每一个细节，难以复用、扩展。</p>
<p>面向对象：抽象化事物，建立模型。</p>
<p>函数式编程：强调将计算过程分解成可复用的函数，MAP方法。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">auto add &#x3D; [](int a,int b) -&gt; int &#123;return a+b&#125;;</span><br></pre></td></tr></table></figure>

<p>泛型编程：STL，编写完全一般化并可重复使用的算法，其效率与针对某特定数据类型而设计的算法相同；泛型：在多种数据类型上皆可操作；将算法与数据结构完全分离。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">template &lt;typename T,typename U&gt;</span><br><span class="line">auto add(T a, U, b) -&gt; decltype(a+b)</span><br><span class="line">return a + b</span><br></pre></td></tr></table></figure>



<h2 id="3、程序执行的底层"><a href="#3、程序执行的底层" class="headerlink" title="3、程序执行的底层"></a>3、程序执行的底层</h2><h3 id="C源码—编译—》对象文件—链接—》可执行程序"><a href="#C源码—编译—》对象文件—链接—》可执行程序" class="headerlink" title="C源码—编译—》对象文件—链接—》可执行程序"></a>C源码—编译—》对象文件—链接—》可执行程序</h3><p>编译时：语法检查，一个源码生成一个目标文件</p>
<p>对象文件：存储各种各样定义</p>
<p>链接：需将所有对象文件定义捏合在一起</p>
<p>定义：函数具体的实现过程在这（有地址空间的为定义）</p>
<p>声明：说有这样一个东西（无地址空间为声明），作用于编译阶段用于语法检查，在调用函数时做语法检查，仅包含函数传入参数与返回值，并不关心函数内部</p>
<p>nm -C main.O </p>
<p>查看main.O该对象文件内容，main.O中printf由系统库实现，add由自定库实现</p>
<p>为何要分开定义与声明？ </p>
<h3 id="h头文件—》放置声明-源文件—》放置定义"><a href="#h头文件—》放置声明-源文件—》放置定义" class="headerlink" title=".h头文件—》放置声明   源文件—》放置定义"></a>.h头文件—》放置声明   源文件—》放置定义</h3><p>把定义放在头文件往往会产生bug</p>
<p>apt-get install vim.deb; ctrl +t 打开中断</p>
<p>凡是未定义（undefined）、冲突（duplicate:符号定义有2个）的错误—》一般是链接阶段的错误；</p>
<h2 id="4、google测试框架"><a href="#4、google测试框架" class="headerlink" title="4、google测试框架"></a>4、google测试框架</h2><p>要实现第三方模块功能的引入—》引入头文件 .h</p>
<p>其定义压缩在一起生成了库文件：静态链接库： .lib</p>
<p>IDE：集成开发环境=文本(vim,gcc) + 编译(g++) + 调试(gdb,lldb)</p>
<h3 id="添加谷歌测试框架"><a href="#添加谷歌测试框架" class="headerlink" title="添加谷歌测试框架"></a>添加谷歌测试框架</h3><p>使用make命令</p>
<p>一般未定义、重复定义的错误：一般均出现在链接阶段的错误。</p>
<p>而找不到头文件的错误，一般出现在预编译阶段，需要添加上头文件的编译路径。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">add</span><span class="params">(<span class="keyword">int</span> a, <span class="keyword">int</span> b)</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a + b</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">TEST(test, add1)&#123;</span><br><span class="line">    EXPECT_EQ(add(<span class="number">3</span>,<span class="number">4</span>),<span class="number">7</span>);</span><br><span class="line">    EXPECT_NQ(add(<span class="number">3</span>,<span class="number">4</span>),<span class="number">6</span>);</span><br><span class="line">    EXPECT_LT(add(<span class="number">3</span>,<span class="number">4</span>),<span class="number">8</span>);</span><br><span class="line">    EXPECT_LE(add(<span class="number">3</span>,<span class="number">4</span>),<span class="number">7</span>);</span><br><span class="line">    EXPECT_GT(add(<span class="number">3</span>,<span class="number">4</span>),<span class="number">6</span>);</span><br><span class="line">    EXPECT_GE(add(<span class="number">3</span>,<span class="number">4</span>),<span class="number">7</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">TEST(test, add2)&#123;</span><br><span class="line">    EXPECT_EQ(add(<span class="number">3</span>,<span class="number">4</span>),<span class="number">7</span>);</span><br><span class="line">    EXPECT_NQ(add(<span class="number">3</span>,<span class="number">4</span>),<span class="number">7</span>);</span><br><span class="line">    EXPECT_LT(add(<span class="number">3</span>,<span class="number">4</span>),<span class="number">7</span>);</span><br><span class="line">    EXPECT_LE(add(<span class="number">3</span>,<span class="number">4</span>),<span class="number">7</span>);</span><br><span class="line">    EXPECT_GT(add(<span class="number">3</span>,<span class="number">4</span>),<span class="number">7</span>);</span><br><span class="line">    EXPECT_GE(add(<span class="number">3</span>,<span class="number">4</span>),<span class="number">7</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>谷歌测试框架中Run_All：1、能够输出彩色字体；2、能够动态地获取知道有多少个测试用例</p>
<h3 id="使用printf输出彩色信息"><a href="#使用printf输出彩色信息" class="headerlink" title="使用printf输出彩色信息"></a>使用printf输出彩色信息</h3><p>使用printf输出信息之前，可以在printf添加配置参数，调整输出的字体颜色。以\033[开头，以m结尾</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">printf</span>(<span class="string">"\033[1;33;41madd(3,4) = %d\n"</span>,add(<span class="number">3</span>,<span class="number">4</span>));</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"hello world\n"</span>);</span><br></pre></td></tr></table></figure>

<p>两行的内容均会改变颜色，因为底层的信息决定了显示的颜色，<strong>而终端的程序就是****用来显示底层信息</strong>的。我们上述的修改是修改了自己配置颜色信息的部分，因此Terminal看到了设置背景色、前景色之后时，之后打印均按照该信息进行，直到后续碰到谷歌框架配置颜色信息的代码时，才按照该框架的配置来显示颜色。</p>
<p>在该配置中0为重置所有属性，故可用下列代码确保仅一行输出改变颜色,\033[0m</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">printf</span>(<span class="string">"\033[1;33;41madd(3,4) = %d\n\033[0m"</span>,add(<span class="number">3</span>,<span class="number">4</span>));</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">"hello world\n"</span>);</span><br></pre></td></tr></table></figure>



<h3 id="实现调试信息log日志打印功能"><a href="#实现调试信息log日志打印功能" class="headerlink" title="实现调试信息log日志打印功能"></a>实现调试信息log日志打印功能</h3><p>在大型工程中同样的调试信息输出代码很常见，故难以判断调试信息在哪输出，因此需要能输出功能更丰富的输出调试信息。</p>
<p>预处理命令：宏定义#define :1、定义符号常量；2、定义傻瓜表达式；3、定义代码段</p>
<p>宏做的事情就是最基本的替换，发生在预处理阶段</p>
<p><em><em>C源码–预处理–》待编译      +  代码 –编译</em>–目标文件–链接–》可执行文件</em></p>
<p>g++ -E :单独执行预处理阶段</p>
<p>最终决定程序功能的并不是C源码，而是待编译源码。因此需要经过预处理阶段之后补充代码之后，才能够正确的实现功能。</p>
<p>#define:宏定义，只做基础的替换，而不做语法检查，且在编译器的视角中，宏定义一定要是一行代码。</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> s(a,b) a*b</span></span><br><span class="line"></span><br><span class="line">s(<span class="keyword">int</span>, p) = &amp;n;</span><br><span class="line"></span><br><span class="line">#这句代码是正确的，因为define并不检查语法，而是只做基础替换，替换后变为： <span class="keyword">int</span> *p = &amp;n；</span><br><span class="line"></span><br><span class="line">s(<span class="number">3</span>+<span class="number">6</span>,<span class="number">4</span>);</span><br><span class="line">#预处理后成为<span class="number">3</span>+<span class="number">6</span>*<span class="number">4</span>；因此输出为<span class="number">27</span>，而不是<span class="number">4</span>*<span class="number">9</span>=<span class="number">36</span></span><br><span class="line"></span><br><span class="line">#define P(a)&#123;\</span><br><span class="line">               <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, d);\&#125;</span><br><span class="line">#利用反斜杠让编译器认为上面的宏定义其实是一行代码</span><br><span class="line"></span><br><span class="line">#预定义的宏</span><br><span class="line">#_DATE_ 日期 #_TIME_ 时间 #_LINE_ 行号 #_FILE_ 文件名 </span><br><span class="line">#_func_ 函数名/非标准 #_FUNC_ 函数名/标准 </span><br><span class="line">#_PRETTY_FUNCTION_ 更详细的函数信息</span><br><span class="line">这些预定义的宏信息可用于检查版本，同样也可用于调试信息<span class="built_in">log</span>日志打印</span><br><span class="line">    </span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> log(msg) &#123;\</span></span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"[%s : %s : %d] %s\n"</span>, __FILE__, __func__, __LINE__, msg) ;\</span><br><span class="line">        &#125;</span><br><span class="line">    故通过<span class="built_in">log</span>能够打印出调试信息从而进行分析</span><br><span class="line">如何根据上述地修改下，实现任意参数的宏，变参函数、变参宏</span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> log(frm, args...) &#123;\</span></span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"[%s : %s : %d] %s\n"</span>, __FILE__, __func__, __LINE__, msg) ;\</span><br><span class="line">        <span class="built_in">printf</span>(frm,##args);\</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">"\n"</span>);\</span><br><span class="line">        &#125;</span><br><span class="line"> 这样就实现了一个外在表现像是<span class="built_in">printf</span>函数的宏，其输出信息会更多许多</span><br></pre></td></tr></table></figure>

<p>#include：将后面文件内容原封不动地拷被至该位置，故待编译源码才能完整地反映功能。</p>
<p>#const：分配空间</p>
<h3 id="预处理命令-条件编译"><a href="#预处理命令-条件编译" class="headerlink" title="预处理命令-条件编译"></a>预处理命令-条件编译</h3><p>如何确保在发布版中没有日志信息，即需要用简单的方式对日志信息创建开关，必须以#endif 结尾</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">ifdef</span> DEBUG <span class="comment">//是否定义了DEBUG宏</span></span></span><br></pre></td></tr></table></figure>

<p>预处理的条件编译只有一个作用：做代码剪裁，使用该命令决定留下哪些代码</p>
<h3 id="实现EXCEPT系列封装"><a href="#实现EXCEPT系列封装" class="headerlink" title="实现EXCEPT系列封装"></a>实现EXCEPT系列封装</h3><p>将谷歌测试框架的头文件换成自己的头文件，并编写自己头文件程序完成同样代码的编译；</p>
<p>1、实现TEST方法；2、实现未卜先知函数RUN_ALL_TEST；3、实现相等、不等、小于等判断方法，可判断不是由函数封装出来的，而是用宏进行封装；</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">ifndef</span> _MYTEST_H</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> _MYTEST_H</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="meta-keyword">define</span> EXPECT_EQ(a,b)&#123;\</span></span><br><span class="line">     <span class="keyword">if</span>(!((a) == (b))&#123;\</span><br><span class="line">     <span class="built_in">print</span>(<span class="string">"error\n"</span>);&#125;&#125;</span><br><span class="line"></span><br><span class="line">#define EXPECT_NE(a,b)&#123;\</span><br><span class="line">     <span class="keyword">if</span>(!((a) != (b))&#123;\</span><br><span class="line">     <span class="built_in">print</span>(<span class="string">"error\n"</span>);&#125;&#125;</span><br><span class="line"></span><br><span class="line">#define EXPECT_EQ(a,b)&#123;\</span><br><span class="line">     <span class="keyword">if</span>(!((a) &lt; (b))&#123;\</span><br><span class="line">     <span class="built_in">print</span>(<span class="string">"error\n"</span>);&#125;&#125;</span><br><span class="line">其实此处代码可以进行复用，来使代码变得简洁，用宏能做的基础替换来进行复用。</span><br><span class="line">#define EXPECT(a, comp, b)&#123;\</span><br><span class="line">      <span class="keyword">if</span>(!((a) comp (b))&#123;\</span><br><span class="line">           <span class="built_in">print</span>(<span class="string">"error\n"</span>);&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">#define EXPECT_EQ(a, b) EXPECT(a, == ,b)</span><br><span class="line">#define EXPECT_NE(a, b) EXPECT(a, != ,b)</span><br><span class="line">#define EXPECT_LT(a, b) EXPECT(a, &lt; ,b) </span><br><span class="line">#define EXPECT_LE(a, b) EXPECT(a, &lt;= ,b)</span><br><span class="line">#define EXPECT_GT(a, b) EXPECT(a, &gt; ,b)</span><br><span class="line">#define EXPECT_GE(a, b) EXPECT(a, &gt;= ,b)</span><br><span class="line"></span><br><span class="line">TEST应当是宏，在预编译后应当展开为函数的头部信息</span><br><span class="line">#define TEST(a, b) <span class="keyword">void</span> a##_##b()</span><br><span class="line"></span><br><span class="line">如何实现RUN_ALL_TEST未卜先知函数</span><br><span class="line">如何确保将测试用例函数信息写入存储区：注册函数</span><br><span class="line">#define TEST(a, b)\</span><br><span class="line"><span class="keyword">void</span> a##_##b();\</span><br><span class="line">__attribute__((constructor))\</span><br><span class="line"><span class="keyword">void</span> reg_##a##_##b()&#123;\</span><br><span class="line">    add_test_func(a##_##b, #a<span class="number">'.'</span>#b);\</span><br><span class="line">    <span class="keyword">return</span> ;\</span><br><span class="line">&#125;</span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">struct&#123;</span><br><span class="line">    <span class="keyword">void</span>(*func)();</span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">char</span> *func_name;</span><br><span class="line">&#125; func_arr[<span class="number">100</span>];<span class="comment">//并非动态存储，而是只能存储100个，可用链表作用来动态开辟空间</span></span><br><span class="line">int_func_cont = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">void</span> add_test_func(<span class="keyword">void</span>(*func)(), <span class="keyword">const</span> *name)&#123;</span><br><span class="line">    func_arr[func_cnt].func =func;</span><br><span class="line">    func_Arr[func_cnt].func_name = name;</span><br><span class="line">    func_cnt += <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">return</span> ;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> RUN_ALLO_TEST&#123;\</span><br><span class="line">      <span class="comment">//遍历每一个测试用例函数（如何遍历，指向函数的指针,有一个存储区存储所有测试函数用例的地址，使用struct结构来设计存储区</span></span><br><span class="line">    <span class="comment">//依次每一个测试用例函数</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; func_cntr; i++)&#123;</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">"[  RUN  ]%S\n"</span>,func_arr[i]-&gt;name);</span><br><span class="line">        func_arr[i].func();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">                 &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#endif</span><br></pre></td></tr></table></figure>



<h2 id="5、简单算法"><a href="#5、简单算法" class="headerlink" title="5、简单算法"></a>5、简单算法</h2><p>二分查找：在一个有序数组中查找一个数据是否存在；二分函数：二分查找如何处理浮点型数据，连续函数；二分答案</p>
<p>本质：二分查找解决的问题：求解单调函数F(x)，函数与数组关系，其实和有序数组查找值一样的方法；</p>
<p>应用特点：给出X很好求，但F(X)并不好求。对于F(X) = 2X,这种正反均好求时，用不着二分查找；而对于在数组中，给出数组下标容易得出值，但给出值查找下标较为困难。</p>
<h3 id="简单版快速排序："><a href="#简单版快速排序：" class="headerlink" title="简单版快速排序："></a>简单版快速排序：</h3><p>核心：partation方法，分区方法，</p>
<p>头部指针、尾部指针：1、先尾部指针，找一个小于基准值放前面；2、再头部指针：找一个大于基准值的放后面；3、头尾指针依次进行交替，直至指针指向同一空位置；</p>
<p>写一个用于测试快速排序的程序：<em>TEST.H</em></p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">define</span> TEST(func, arr, l, r)&#123;</span></span><br><span class="line">   <span class="keyword">int</span> *temp = (<span class="keyword">int</span>*)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">int</span>) * n);<span class="comment">//传入数组</span></span><br><span class="line">   <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt;n; i++) temp[i] = arr[i];<span class="comment">//将arr中函数拷贝到temp中</span></span><br><span class="line">   func(temp, <span class="number">0</span> ,n<span class="number">-1</span>);</span><br><span class="line">   <span class="keyword">if</span>(check(temp, <span class="number">0</span>, n<span class="number">-1</span>))&#123;</span><br><span class="line">       <span class="built_in">print</span>(<span class="string">"[    OK    ]%s\n"</span>, #func);</span><br><span class="line">   &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">       <span class="built_in">print</span>(<span class="string">"[    FAILED    ]%s\n"</span>, #func); </span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">check</span><span class="params">(<span class="keyword">int</span> *arr, <span class="keyword">int</span> l, <span class="keyword">int</span> r)</span></span>&#123;</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">int</span> i = l + <span class="number">1</span>; i &lt;= r; i++)&#123;</span><br><span class="line">        <span class="keyword">if</span>(arr[i] &lt; arr[i<span class="number">-1</span>]) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> *<span class="title">getRandData</span><span class="params">(<span class="keyword">int</span> n)</span></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> *arr = (<span class="keyword">int</span>*)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">int</span>) * n);<span class="comment">//分配位置</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; n; i++) arr[i] = rand() % n;</span><br><span class="line">    <span class="keyword">return</span> arr;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">int</span> main&#123;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>





<h4 id="version1"><a href="#version1" class="headerlink" title="version1"></a>version1</h4><p>partation：选择待排序区间的第一个元素作为基准值，将小于基准值的元素放在前面，大于基准值的元素放在后面，前后指针重合时，再分别对前后两部分进行快速排序的操作。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">quick_sort_v1</span><span class="params">(<span class="keyword">int</span> *arr_, <span class="keyword">int</span> l , <span class="keyword">int</span> r)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(l &gt;= r) <span class="keyword">return</span>; <span class="comment">//递归过程第一步必然要进行边界判断</span></span><br><span class="line">    <span class="keyword">int</span> x = <span class="number">1</span>; y = r; z = arr[];<span class="comment">// Z为基准值应该在的位置</span></span><br><span class="line">    <span class="keyword">while</span>(x &lt; y)&#123;</span><br><span class="line">        <span class="keyword">while</span> (x &lt; y &amp;&amp; arr[y] &gt;= z) --y;</span><br><span class="line">        <span class="keyword">if</span>(x &lt; y) arr[x++] = arr[y];<span class="comment">//放至头指针指向的空位</span></span><br><span class="line">        <span class="keyword">while</span> (x &lt; y &amp;&amp; arr[x] &lt;= z) ++x;</span><br><span class="line">        <span class="keyword">if</span>(x &lt; y) arr[y--] = arr[x];</span><br><span class="line">    &#125;</span><br><span class="line">    arr[x] = z;<span class="comment">//最后将基准值放回其原来应该在的位置</span></span><br><span class="line">    quick_sort_v1(arr, l, x - <span class="number">1</span>);</span><br><span class="line">    quick_sort_va(arr, x + <span class="number">1</span>, r);</span><br><span class="line">    <span class="keyword">return</span> ;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>算法工程师平时考虑的是时间复杂度吗？</p>
<p>大环境下的共识：你和你身边的同事都是算法工程师，因此nlogn时间复杂度算法都能想到，关键在于在实现时代码实现的细节；</p>
<h4 id="version2：单边递归法"><a href="#version2：单边递归法" class="headerlink" title="version2：单边递归法"></a>version2：单边递归法</h4><p>当本层的快速排序做完partation操作时，会分别对左右两边进行递归操作，因此相当于一个二叉树的结构；</p>
<p>单边递归法核心思想：作为一个主管，在要被优化掉之前，做下一层的活。当前的version1函数，partation做完之后等着左右两边，可以让左半边继续递归，但右半边交给当前层程序进行执行。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">quick_sort_v2</span><span class="params">(<span class="keyword">int</span> *arr_, <span class="keyword">int</span> l , <span class="keyword">int</span> r)</span></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(l &lt; r)&#123; </span><br><span class="line">        <span class="keyword">int</span> x = l ; y = r; z = arr[l];<span class="comment">// Z为基准值应该在的位置</span></span><br><span class="line">        <span class="keyword">while</span>(x &lt; y)&#123;</span><br><span class="line">            <span class="keyword">while</span> (x &lt; y &amp;&amp; arr[y] &gt;= z) --y;</span><br><span class="line">            <span class="keyword">if</span>(x &lt; y) arr[x++] = arr[y];<span class="comment">//放至头指针指向的空位</span></span><br><span class="line">            <span class="keyword">while</span> (x &lt; y &amp;&amp; arr[x] &lt;= z) ++x;</span><br><span class="line">            <span class="keyword">if</span>(x &lt; y) arr[y--] = arr[x];</span><br><span class="line">        &#125;</span><br><span class="line">        arr[x] = z;<span class="comment">//最后将基准值放回其原来应该在的位置</span></span><br><span class="line">        quick_sort_v2(arr, l, x - <span class="number">1</span>);</span><br><span class="line">        l = x + <span class="number">1</span>;</span><br><span class="line">    &#125;<span class="comment">//使用while，做完partation操作后，左半边排序通过递归来进行，</span></span><br><span class="line">    <span class="comment">//右半边的排序通过修改本层的</span></span><br><span class="line">    <span class="keyword">return</span> ;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="version3：无监督优化"><a href="#version3：无监督优化" class="headerlink" title="version3：无监督优化"></a>version3：无监督优化</h4><p>凡是判断坐标范围超界的判断：均为监督项，无监督优化：将监督项干掉；</p>
<p>先以插入排序来举例子：</p>
<p>插入排序思想：将无序序列分成两部分，前半部分为已排序区，后半部分为未排序区，每次从未排序区的头部选择一个元素，插入至已排序区中。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">insert_sort_v1</span><span class="params">(<span class="keyword">int</span> *arr, <span class="keyword">int</span> l, <span class="keyword">int</span> r)</span></span>&#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = l + <span class="number">1</span>; i &lt;= r; i++)&#123;</span><br><span class="line">        <span class="keyword">int</span> j = i;</span><br><span class="line">        <span class="keyword">while</span>(j &gt; <span class="number">0</span> &amp;&amp; arr[j] &lt; arr[j - <span class="number">1</span>])&#123;</span><br><span class="line">            swap(arr[j], arr[j<span class="number">-1</span>]);</span><br><span class="line">            --j;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> ;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>无监督思想：为何需要监督项，确保指针访问不越界，那么如何才能去掉这个监督项看上述while(j &gt; 0 &amp;&amp; arr[j] &lt; arr[j - 1])，只有当前插入的元素，是当前已排序区间的最小值，才会越界；因此，先做一个预处理，将该全局范围内的最小值先放置第一位，则不可能发生这种越界操作，则不再需要插入排序中的监督项。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">insert_sort_v2</span><span class="params">(<span class="keyword">int</span> *arr, <span class="keyword">int</span> l, <span class="keyword">int</span> r)</span></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> ind = l;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = l + <span class="number">1</span>; i &lt;= r; i++)&#123;</span><br><span class="line">        <span class="keyword">if</span>(arr[ind] &gt; arr[i]) ind = i;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//插入排序是一个稳定的排序，而直接交换两个位置的值会破坏其稳定性</span></span><br><span class="line">    <span class="comment">//找到全局最小值位置后，应当将其依次一个个换至最前面</span></span><br><span class="line">    <span class="keyword">while</span> (ind &gt; l)&#123;</span><br><span class="line">        swap(arr[ind], arr[ind <span class="number">-1</span>]);</span><br><span class="line">        --ind;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = l + <span class="number">1</span>; i &lt;= r; i++)&#123;</span><br><span class="line">        <span class="keyword">int</span> j = i;</span><br><span class="line">        <span class="keyword">while</span>(j &gt; <span class="number">0</span> &amp;&amp; arr[j] &lt; arr[j - <span class="number">1</span>])&#123;</span><br><span class="line">            swap(arr[j], arr[j<span class="number">-1</span>]);</span><br><span class="line">            --j;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> ;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>那么如何实现无监督的快速排序呢？快速排序中的partation过程，小于基准值放在前，大于的放在后；逻辑上讲，确定基准值后，其前后元素的数量就已经定了，由于基准值前后的位置数量是固定的，则有前一个值往后移、则必然后后面一个元素向前移。</p>
<p>故可以头尾指针同时向中间走，且两者同时进行交换，这样就能去掉快速排序过程中其所谓的监督项了。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">quick_sort_v3</span><span class="params">(<span class="keyword">int</span> *arr_, <span class="keyword">int</span> l , <span class="keyword">int</span> r)</span></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(l &lt; r)&#123;</span><br><span class="line">        <span class="keyword">int</span> x = <span class="number">1</span>, y = r, z = arr[l];</span><br><span class="line">        <span class="keyword">do</span>&#123;</span><br><span class="line">            <span class="keyword">while</span>(arr[x] &lt; z) ++x;</span><br><span class="line">            <span class="keyword">while</span>(arr[y] &gt; z) --y;</span><br><span class="line">            <span class="keyword">if</span>(x &lt;= y)&#123;</span><br><span class="line">                swap(arr[x], arr[y]);</span><br><span class="line">                ++x, --y;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;<span class="keyword">while</span>(x &lt;= y);</span><br><span class="line">    quick_sort_v3(arr, l, y);</span><br><span class="line">    l = x ;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> ;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>无监督的算法优化思维是一种非常重要的代码优化思维。</p>
<h4 id="version4：基准值选择优化"><a href="#version4：基准值选择优化" class="headerlink" title="version4：基准值选择优化"></a>version4：基准值选择优化</h4><p>核心思维：快速排序时间复杂度，T(n) = n * h，其中h为递归二叉树的树高，而递归二叉树最多为n个节点，logn &lt; h &lt; n；则nlogn &lt; T(n) &lt; n**2</p>
<p>如何让快排的时间复杂度稳定在nlogn：控制二叉树树高，即每一次区分左右树时，尽量让左右两边平分，即基准值能平分数组。</p>
<p>方法一：三点取中法，在头指针l，尾指针r，中间元素指针m，三者指向的值之间，选取中位的那个数值作为基准值。</p>
<h2 id="6、虚函数"><a href="#6、虚函数" class="headerlink" title="6、虚函数"></a>6、虚函数</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span> &#123;</span></span><br><span class="line">    <span class="keyword">public</span> :</span><br><span class="line">       <span class="function"><span class="keyword">void</span> <span class="title">say</span><span class="params">()</span></span>&#123;</span><br><span class="line">           <span class="built_in">cout</span> &lt;&lt; <span class="string">"this is Class A"</span> &lt;&lt; <span class="built_in">endl</span>;</span><br><span class="line">       &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">B</span> :</span> <span class="keyword">public</span> A &#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">       <span class="function"><span class="keyword">void</span> <span class="title">say</span><span class="params">()</span></span>&#123;</span><br><span class="line">           <span class="built_in">cout</span> &lt;&lt; <span class="string">"this is class B"</span> &lt;&lt; <span class="built_in">endl</span>;</span><br><span class="line">       &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</span><br><span class="line">    B b;</span><br><span class="line">    A &amp;a = b;</span><br><span class="line">    A *c = &amp;b;</span><br><span class="line">    b.say(); <span class="comment">//会调用B类say方法</span></span><br><span class="line">    a.say();<span class="comment">//会调用A类say方法</span></span><br><span class="line">    c-&gt;say();<span class="comment">//会调用A类say方法</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//普通的成员函数方法是跟着类走的，根据其类类别，来判断调用哪种成员方法</span></span><br><span class="line"><span class="comment">//而虚函数的方法，其调用的方法是跟着对象走的</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">C</span> &#123;</span></span><br><span class="line">    <span class="keyword">public</span> :</span><br><span class="line">       <span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">say</span><span class="params">()</span></span>&#123;  <span class="comment">//前面加virtual,使其变成虚函数</span></span><br><span class="line">           <span class="built_in">cout</span> &lt;&lt; <span class="string">"this is Class A"</span> &lt;&lt; <span class="built_in">endl</span>;</span><br><span class="line">       &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">D</span> :</span> <span class="keyword">public</span> C &#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">       <span class="function"><span class="keyword">void</span> <span class="title">say</span><span class="params">()</span></span>&#123; <span class="comment">//父类的方法定义为虚函数，则其继承的子类的对应方法也会变成虚函数</span></span><br><span class="line">           <span class="built_in">cout</span> &lt;&lt; <span class="string">"this is class B"</span> &lt;&lt; <span class="built_in">endl</span>;</span><br><span class="line">       &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span>&#123;</span><br><span class="line">    B b;</span><br><span class="line">    A &amp;a = b;<span class="comment">//a虽然是A类型的引用，但它绑定的是B类型的对象</span></span><br><span class="line">    A *c = &amp;b;<span class="comment">//间接引用C时，C虽然指针类型，但它指向的是B类的对象，因此也是调用B类方法</span></span><br><span class="line">    b.say(); <span class="comment">//会调用B类say方法</span></span><br><span class="line">    a.say();<span class="comment">//会调用A类say方法</span></span><br><span class="line">    c-&gt;say();<span class="comment">//会调用A类say方法</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="为什么虚函数可以跟着对象走："><a href="#为什么虚函数可以跟着对象走：" class="headerlink" title="为什么虚函数可以跟着对象走："></a>为什么虚函数可以跟着对象走：</h3><p>任何一个对象都会占据一片存储空间，当对象中存在虚函数时，其底层存储区域中的第一个位置会记录一个地址；该地址指向一张虚函数的表vtable，表中每一项都存储的是虚函数。</p>
<p>因此虚函数是跟着对象走的，不管是何种类型的对象，都会指向了虚函数表，从而调用了当前对象所绑定的虚函数方法。 </p>
<p>假设虚函数类型为T类型，则虚函数表首地址为T* 类型， 则存储T*类型数据区的数据为T**类型。因此可用C语言中指针来提取虚函数。但若用此方法来提取带参数的虚函数时，可能会导致参数混乱。</p>
<h3 id="this指针"><a href="#this指针" class="headerlink" title="this指针"></a>this指针</h3><p>原因是：在成员方法中的特殊变量：this指针,在成员方法中，看着是一个参数，实则会添加一个隐藏参数：this指针。因此两个参数：一个是this指针指向的地址，一个才是真正的传递参数。</p>
<p>this指针其实是一个变量，是成员方法的隐藏参数。</p>
<h1 id="C-基础"><a href="#C-基础" class="headerlink" title="C++基础"></a>C++基础</h1><h2 id="基本语法"><a href="#基本语法" class="headerlink" title="基本语法"></a>基本语法</h2><ul>
<li><strong>对象 -</strong> 对象具有状态和行为。例如：一只狗的状态 - 颜色、名称、品种，行为 - 摇动、叫唤、吃。对象是类的实例。</li>
<li><strong>类 -</strong> 类可以定义为描述对象行为/状态的模板/蓝图。</li>
<li><strong>方法 -</strong> 从基本上说，一个方法表示一种行为。一个类可以包含多个方法。可以在方法中写入逻辑、操作数据以及执行所有的动作。</li>
<li><strong>即时变量 -</strong> 每个对象都有其独特的即时变量。对象的状态是由这些即时变量的值创建的。</li>
</ul>
<h2 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h2><table>
<thead>
<tr>
<th>布尔型</th>
<th>bool</th>
</tr>
</thead>
<tbody><tr>
<td>字符型</td>
<td>char</td>
</tr>
<tr>
<td>整型</td>
<td>int</td>
</tr>
<tr>
<td>浮点型</td>
<td>float</td>
</tr>
<tr>
<td>双浮点型</td>
<td>double</td>
</tr>
<tr>
<td>无类型</td>
<td>void</td>
</tr>
<tr>
<td>宽字符型</td>
<td>wchar_t</td>
</tr>
</tbody></table>
<p> <strong>endl</strong>，这将在每一行后插入一个换行符，&lt;&lt; 运算符用于向屏幕传多个值</p>
<p>可以使用 <strong>typedef</strong> 为一个已有的类型取一个新的名字。下面是使用 typedef 定义一个新类型的语法：</p>
<p>现在，下面的声明是完全合法的，它创建了一个整型变量 distance：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="keyword">int</span> feet;</span><br><span class="line">feet distance;</span><br></pre></td></tr></table></figure>

<h3 id="枚举类型"><a href="#枚举类型" class="headerlink" title="枚举类型"></a>枚举类型</h3><p>枚举类型(enumeration)是C++中的一种派生数据类型，它是由用户定义的若干枚举常量的集合。建枚举，需要使用关键字 <strong>enum</strong>。枚举类型的一般形式为：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">enum</span> 枚举名&#123; </span><br><span class="line">     标识符[=整型常数], </span><br><span class="line">     标识符[=整型常数], </span><br><span class="line">... </span><br><span class="line">    标识符[=整型常数]</span><br><span class="line">&#125; 枚举变量;</span><br><span class="line"><span class="comment">//如果枚举没有初始化, 即省掉"=整型常数"时, 则从第一个标识符开始。</span></span><br><span class="line"><span class="comment">//例如，下面的代码定义了一个颜色枚举，变量 c 的类型为 color。最后，c 被赋值为 "blue"。</span></span><br><span class="line"><span class="keyword">enum</span> color &#123; red, green, blue &#125; c;</span><br><span class="line">c = blue;</span><br></pre></td></tr></table></figure>

<h2 id="变量类型"><a href="#变量类型" class="headerlink" title="变量类型"></a>变量类型</h2><p>变量其实只不过是程序可操作的存储区的名称。C++ 中每个变量都有指定的类型，类型决定了变量存储的大小和布局，该范围内的值都可以存储在内存中，运算符可应用于变量上。</p>
<table>
<thead>
<tr>
<th>bool</th>
<th align="center">存储值 true 或 false。</th>
</tr>
</thead>
<tbody><tr>
<td>char</td>
<td align="center">通常是一个字符（八位）。这是一个整数类型。</td>
</tr>
<tr>
<td>int</td>
<td align="center">对机器而言，整数的最自然的大小。</td>
</tr>
<tr>
<td>float</td>
<td align="center">单精度浮点值。单精度是这样的格式，1位符号，8位指数，23位小数。<img src="https://www.runoob.com/wp-content/uploads/2014/09/v2-749cc641eb4d5dafd085e8c23f8826aa_hd.png" alt="img"></td>
</tr>
<tr>
<td>double</td>
<td align="center">双精度浮点值。双精度是1位符号，11位指数，52位小数。<img src="https://www.runoob.com/wp-content/uploads/2014/09/v2-48240f0e1e0dd33ec89100cbe2d30707_hd.png" alt="img"></td>
</tr>
<tr>
<td>void</td>
<td align="center">表示类型的缺失。</td>
</tr>
<tr>
<td>wchar_t</td>
<td align="center">宽字符类型。</td>
</tr>
</tbody></table>
<p>变量定义就是告诉编译器在何处创建变量的存储，以及如何创建变量的存储。变量定义指定一个数据类型，并包含了该类型的一个或多个变量的列表，</p>
<p>变量声明向编译器保证变量以给定的类型和名称存在，这样编译器在不需要知道变量完整细节的情况下也能继续进一步的编译。变量声明只在编译时有它的意义，在程序连接时编译器需要实际的变量声明。</p>
<p>当您使用多个文件且只在其中一个文件中定义变量时（定义变量的文件在程序连接时是可用的），变量声明就显得非常有用。您可以使用 <strong>extern</strong> 关键字在任何地方声明一个变量。虽然您可以在 C++ 程序中多次声明一个变量，但变量只能在某个文件、函数或代码块中被定义一次。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 变量声明</span></span><br><span class="line"><span class="keyword">extern</span> <span class="keyword">int</span> a, b;</span><br><span class="line"><span class="keyword">extern</span> <span class="keyword">int</span> c;</span><br><span class="line"><span class="keyword">extern</span> <span class="keyword">float</span> f;</span><br><span class="line">  </span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">  <span class="comment">// 变量定义</span></span><br><span class="line">  <span class="keyword">int</span> a, b;</span><br><span class="line">  <span class="keyword">int</span> c;</span><br><span class="line">  <span class="keyword">float</span> f;</span><br><span class="line"> </span><br><span class="line">  <span class="comment">// 实际初始化</span></span><br><span class="line">  a = <span class="number">10</span>;</span><br><span class="line">  b = <span class="number">20</span>;</span><br><span class="line">  c = a + b;</span><br><span class="line"> </span><br><span class="line">  <span class="built_in">cout</span> &lt;&lt; c &lt;&lt; <span class="built_in">endl</span> ;</span><br><span class="line"> </span><br><span class="line">  f = <span class="number">70.0</span>/<span class="number">3.0</span>;</span><br><span class="line">  <span class="built_in">cout</span> &lt;&lt; f &lt;&lt; <span class="built_in">endl</span> ;</span><br><span class="line"> </span><br><span class="line">  <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>同样的，在函数声明时，提供一个函数名，而函数的实际定义则可以在任何地方进行。例如</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 函数声明</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">func</span><span class="params">()</span></span>;</span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// 函数调用</span></span><br><span class="line">    <span class="keyword">int</span> i = func();</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 函数定义</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">func</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>C++ 中有两种类型的表达式：</p>
<ul>
<li><strong>左值（lvalue）：</strong>指向内存位置、的表达式被称为左值（lvalue）表达式。左值可以出现在赋值号的左边或右边。</li>
<li><strong>右值（rvalue）：</strong>术语右值（rvalue）指的是存储在内存中某些地址的数值。右值是不能对其进行赋值的表达式，也就是说，右值可以出现在赋值号的右边，但不能出现在赋值号的左边。</li>
</ul>
<p>变量是左值，因此可以出现在赋值号的左边。数值型的字面值是右值，因此不能被赋值，不能出现在赋值号的左边。下面是一个有效的语句：</p>
<h2 id="变量作用域"><a href="#变量作用域" class="headerlink" title="变量作用域"></a>变量作用域</h2><p>作用域是程序的一个区域，一般来说有三个地方可以定义变量：</p>
<ul>
<li>在函数或一个代码块内部声明的变量，称为局部变量。</li>
<li>在函数参数的定义中声明的变量，称为形式参数。</li>
<li>在所有函数外部声明的变量，称为全局变量。</li>
</ul>
<p>在函数或一个代码块内部声明的变量，称为局部变量。它们只能被函数内部或者代码块内部的语句使用。</p>
<p>在所有函数外部定义的变量（通常是在程序的头部），称为全局变量。全局变量的值在程序的整个生命周期内都是有效的。</p>
<p>在程序中，局部变量和全局变量的名称可以相同，但是在函数内，局部变量的值会覆盖全局变量的值。</p>
<h2 id="字面量"><a href="#字面量" class="headerlink" title="字面量"></a>字面量</h2><p>常量是固定值，在程序执行期间不会改变。这些固定的值，又叫做<strong>字面量</strong>。</p>
<p>常量可以是任何的基本数据类型，可分为整型数字、浮点数字、字符、字符串和布尔值。</p>
<p>在 C++ 中，有两种简单的定义常量的方式：</p>
<ul>
<li>使用 <strong>#define</strong> 预处理器。</li>
<li>使用 <strong>const</strong> 关键字。</li>
</ul>
<h2 id="修饰符类型"><a href="#修饰符类型" class="headerlink" title="修饰符类型"></a>修饰符类型</h2><p>C++ 允许在 <strong>char、int 和 double</strong> 数据类型前放置修饰符。修饰符用于改变基本类型的含义，所以它更能满足各种情境的需求。</p>
<p>修饰符 <strong>signed、unsigned、long 和 short</strong> 可应用于整型，<strong>signed</strong> 和 <strong>unsigned</strong> 可应用于字符型，<strong>long</strong> 可应用于双精度型。</p>
<p>修饰符 <strong>signed</strong> 和 <strong>unsigned</strong> 也可以作为 <strong>long</strong> 或 <strong>short</strong> 修饰符的前缀。例如：<strong>unsigned long int</strong>。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//为了理解 C++ 解释有符号整数和无符号整数修饰符之间的差别，我们来运行一下下面这个短程序：</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"> </span><br><span class="line"><span class="comment">/* </span></span><br><span class="line"><span class="comment"> * 这个程序演示了有符号整数和无符号整数之间的差别</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">   short <span class="keyword">int</span> i;           <span class="comment">// 有符号短整数</span></span><br><span class="line">   short <span class="keyword">unsigned</span> <span class="keyword">int</span> j;  <span class="comment">// 无符号短整数</span></span><br><span class="line"> </span><br><span class="line">   j = <span class="number">50000</span>;</span><br><span class="line"> </span><br><span class="line">   i = j;</span><br><span class="line">   <span class="built_in">cout</span> &lt;&lt; i &lt;&lt; <span class="string">" "</span> &lt;&lt; j;</span><br><span class="line"> </span><br><span class="line">   <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//输出-15536 50000</span></span><br><span class="line"><span class="comment">//上述结果中，无符号短整数 50,000 的位模式被解释为有符号短整数 -15,536</span></span><br></pre></td></tr></table></figure>

<h2 id="存储类"><a href="#存储类" class="headerlink" title="存储类"></a>存储类</h2><p>存储类定义 C++ 程序中变量/函数的范围（可见性）和生命周期。这些说明符放置在它们所修饰的类型之前。下面列出 C++ 程序中可用的存储类：</p>
<ul>
<li>auto</li>
<li>register</li>
<li>static</li>
<li>extern</li>
<li>mutable</li>
<li>thread_local (C++11)</li>
</ul>
<h3 id="auto-存储类"><a href="#auto-存储类" class="headerlink" title="auto 存储类"></a>auto 存储类</h3><p>自 C++ 11 以来，<strong>auto</strong> 关键字用于两种情况：声明变量时根据初始化表达式自动推断该变量的类型、声明函数时函数返回值的占位符。</p>
<h3 id="register-存储类"><a href="#register-存储类" class="headerlink" title="register 存储类"></a>register 存储类</h3><p><strong>register</strong> 存储类用于定义存储在寄存器中而不是 RAM 中的局部变量。这意味着变量的最大尺寸等于寄存器的大小（通常是一个词），且不能对它应用一元的 ‘&amp;’ 运算符（因为它没有内存位置）</p>
<p>寄存器只用于需要快速访问的变量，比如计数器。</p>
<h3 id="static-存储类"><a href="#static-存储类" class="headerlink" title="static 存储类"></a>static 存储类</h3><p><strong>static</strong> 存储类指示编译器在程序的生命周期内保持局部变量的存在，而不需要在每次它进入和离开作用域时进行创建和销毁。因此，使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。</p>
<p>static 修饰符也可以应用于全局变量。当 static 修饰全局变量时，会使变量的作用域限制在声明它的文件内。在 C++ 中，当 static 用在类数据成员上时，会导致仅有一个该成员的副本被类的所有对象共享。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"> </span><br><span class="line"><span class="comment">// 函数声明 </span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">func</span><span class="params">(<span class="keyword">void</span>)</span></span>;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">static</span> <span class="keyword">int</span> count = <span class="number">10</span>; <span class="comment">/* 全局变量 */</span></span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(count--)</span><br><span class="line">    &#123;</span><br><span class="line">       func();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 函数定义</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">func</span><span class="params">( <span class="keyword">void</span> )</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">int</span> i = <span class="number">5</span>; <span class="comment">// 局部静态变量</span></span><br><span class="line">    i++;</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">"变量 i 为 "</span> &lt;&lt; i ;</span><br><span class="line">    <span class="built_in">std</span>::<span class="built_in">cout</span> &lt;&lt; <span class="string">" , 变量 count 为 "</span> &lt;&lt; count &lt;&lt; <span class="built_in">std</span>::<span class="built_in">endl</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="extern-存储类"><a href="#extern-存储类" class="headerlink" title="extern 存储类"></a>extern 存储类</h3><p><strong>extern</strong> 存储类用于提供一个全局变量的引用，全局变量对所有的程序文件都是可见的。当您使用 ‘extern’ 时，对于无法初始化的变量，会把变量名指向一个之前定义过的存储位置。</p>
<p>当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时，可以在其他文件中使用 <em>extern</em> 来得到已定义的变量或函数的引用。可以这么理解，<em>extern</em> 是用来在另一个文件中声明一个全局变量或函数。</p>
<p>extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候，如下所示：</p>
<p>第一个文件：main.cpp</p>
<p>在这里，第二个文件中的 <em>extern</em> 关键字用于声明已经在第一个文件 main.cpp 中定义的 count。现在 ，编译这两个文件，如下所示</p>
<h2 id="mutable-存储类"><a href="#mutable-存储类" class="headerlink" title="mutable 存储类"></a>mutable 存储类</h2><p><strong>mutable</strong> 说明符仅适用于类的对象，这将在本教程的最后进行讲解。它允许对象的成员替代常量。也就是说，mutable 成员可以通过 const 成员函数修改。</p>
<h2 id="thread-local-存储类"><a href="#thread-local-存储类" class="headerlink" title="thread_local 存储类"></a>thread_local 存储类</h2><p>使用 thread_local 说明符声明的变量仅可在它在其上创建的线程上访问。 变量在创建线程时创建，并在销毁线程时销毁。 每个线程都有其自己的变量副本。</p>
<p>thread_local 说明符可以与 static 或 extern 合并。可以将 thread_local 仅应用于数据声明和定义，thread_local 不能用于函数声明或定义。以下演示了可以被声明为 thread_local 的变量：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">thread_local</span> <span class="keyword">int</span> x;  <span class="comment">// 命名空间下的全局变量</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">X</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">thread_local</span> <span class="built_in">std</span>::<span class="built_in">string</span> s; <span class="comment">// 类的static成员变量</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">static</span> <span class="keyword">thread_local</span> <span class="built_in">std</span>::<span class="built_in">string</span> X::s;  <span class="comment">// X::s 是需要定义的</span></span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">foo</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">thread_local</span> <span class="built_in">std</span>::<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; v;  <span class="comment">// 本地变量</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="运算符"><a href="#运算符" class="headerlink" title="运算符"></a>运算符</h2><ul>
<li><p>算术运算符 + - * / % ++ –</p>
</li>
<li><p>关系运算符 == != &gt; &lt; &gt;= &lt;=</p>
</li>
<li><p>逻辑运算符 &amp;&amp; || !</p>
</li>
<li><p>位运算符 </p>
<table>
<thead>
<tr>
<th><strong>&amp;</strong></th>
<th><strong>如果同时存在于两个操作数中，二进制 AND 运算符复制一位到结果中。</strong></th>
<th><strong>(A &amp; B) 将得到 12，即为 0000 1100</strong></th>
</tr>
</thead>
<tbody><tr>
<td>|</td>
<td>如果存在于任一操作数中，二进制 OR 运算符复制一位到结果中。</td>
<td>(A | B) 将得到 61，即为 0011 1101</td>
</tr>
<tr>
<td>^</td>
<td>如果存在于其中一个操作数中但不同时存在于两个操作数中，二进制异或运算符复制一位到结果中。</td>
<td>(A ^ B) 将得到 49，即为 0011 0001</td>
</tr>
<tr>
<td>~</td>
<td>二进制补码运算符是一元运算符，具有”翻转”位效果，即0变成1，1变成0。</td>
<td>(~A ) 将得到 -61，即为 1100 0011，一个有符号二进制数的补码形式。</td>
</tr>
<tr>
<td>&lt;&lt;</td>
<td>二进制左移运算符。左操作数的值向左移动右操作数指定的位数。</td>
<td>A &lt;&lt; 2 将得到 240，即为 1111 0000</td>
</tr>
<tr>
<td>&gt;&gt;</td>
<td>二进制右移运算符。左操作数的值向右移动右操作数指定的位数。</td>
<td>A &gt;&gt; 2 将得到 15，即为 0000 1111</td>
</tr>
</tbody></table>
</li>
<li><p>赋值运算符</p>
<table>
<thead>
<tr>
<th>=</th>
<th>简单的赋值运算符，把右边操作数的值赋给左边操作数</th>
<th>C = A + B 将把 A + B 的值赋给 C</th>
</tr>
</thead>
<tbody><tr>
<td>+=</td>
<td>加且赋值运算符，把右边操作数加上左边操作数的结果赋值给左边操作数</td>
<td>C += A 相当于 C = C + A</td>
</tr>
<tr>
<td>-=</td>
<td>减且赋值运算符，把左边操作数减去右边操作数的结果赋值给左边操作数</td>
<td>C -= A 相当于 C = C - A</td>
</tr>
<tr>
<td>*=</td>
<td>乘且赋值运算符，把右边操作数乘以左边操作数的结果赋值给左边操作数</td>
<td>C *= A 相当于 C = C * A</td>
</tr>
<tr>
<td>/=</td>
<td>除且赋值运算符，把左边操作数除以右边操作数的结果赋值给左边操作数</td>
<td>C /= A 相当于 C = C / A</td>
</tr>
<tr>
<td>%=</td>
<td>求模且赋值运算符，求两个操作数的模赋值给左边操作数</td>
<td>C %= A 相当于 C = C % A</td>
</tr>
<tr>
<td>&lt;&lt;=</td>
<td>左移且赋值运算符</td>
<td>C &lt;&lt;= 2 等同于 C = C &lt;&lt; 2</td>
</tr>
<tr>
<td>&gt;&gt;=</td>
<td>右移且赋值运算符</td>
<td>C &gt;&gt;= 2 等同于 C = C &gt;&gt; 2</td>
</tr>
<tr>
<td>&amp;=</td>
<td>按位与且赋值运算符</td>
<td>C &amp;= 2 等同于 C = C &amp; 2</td>
</tr>
<tr>
<td>^=</td>
<td>按位异或且赋值运算符</td>
<td>C ^= 2 等同于 C = C ^ 2</td>
</tr>
<tr>
<td>|=</td>
<td>按位或且赋值运算符</td>
<td>C |= 2 等同于 C = C | 2</td>
</tr>
</tbody></table>
</li>
<li><p>杂项运算符</p>
</li>
</ul>
<table>
<thead>
<tr>
<th>sizeof</th>
<th><a href="https://www.runoob.com/cplusplus/cpp-sizeof-operator.html" target="_blank" rel="noopener">sizeof 运算符</a>返回变量的大小。例如，sizeof(a) 将返回 4，其中 a 是整数。</th>
</tr>
</thead>
<tbody><tr>
<td>Condition ? X : Y</td>
<td><a href="https://www.runoob.com/cplusplus/cpp-conditional-operator.html" target="_blank" rel="noopener">条件运算符</a>。如果 Condition 为真 ? 则值为 X : 否则值为 Y。</td>
</tr>
<tr>
<td>,</td>
<td><a href="https://www.runoob.com/cplusplus/cpp-comma-operator.html" target="_blank" rel="noopener">逗号运算符</a>会顺序执行一系列运算。整个逗号表达式的值是以逗号分隔的列表中的最后一个表达式的值。</td>
</tr>
<tr>
<td>.（点）和 -&gt;（箭头）</td>
<td><a href="https://www.runoob.com/cplusplus/cpp-member-operators.html" target="_blank" rel="noopener">成员运算符</a>用于引用类、结构和共用体的成员。</td>
</tr>
<tr>
<td>Cast</td>
<td><a href="https://www.runoob.com/cplusplus/cpp-casting-operators.html" target="_blank" rel="noopener">强制转换运算符</a>把一种数据类型转换为另一种数据类型。例如，int(2.2000) 将返回 2。</td>
</tr>
<tr>
<td>&amp;</td>
<td><a href="https://www.runoob.com/cplusplus/cpp-pointer-operators.html" target="_blank" rel="noopener">指针运算符 &amp;</a> 返回变量的地址。例如 &a; 将给出变量的实际地址。</td>
</tr>
<tr>
<td>*</td>
<td><a href="https://www.runoob.com/cplusplus/cpp-pointer-operators.html" target="_blank" rel="noopener">指针运算符 *</a> 指向一个变量。例如，*var; 将指向变量 var。</td>
</tr>
</tbody></table>
<h2 id="循环"><a href="#循环" class="headerlink" title="循环"></a>循环</h2><p>循环控制语句更改执行的正常序列。当执行离开一个范围时，所有在该范围中创建的自动对象都会被销毁。</p>
<table>
<thead>
<tr>
<th align="left">控制语句</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody><tr>
<td align="left"><a href="https://www.runoob.com/cplusplus/cpp-break-statement.html" target="_blank" rel="noopener">break 语句</a></td>
<td align="left">终止 <strong>loop</strong> 或 <strong>switch</strong> 语句，程序流将继续执行紧接着 loop 或 switch 的下一条语句。</td>
</tr>
<tr>
<td align="left"><a href="https://www.runoob.com/cplusplus/cpp-continue-statement.html" target="_blank" rel="noopener">continue 语句</a></td>
<td align="left">引起循环跳过主体的剩余部分，立即重新开始测试条件。</td>
</tr>
<tr>
<td align="left"><a href="https://www.runoob.com/cplusplus/cpp-goto-statement.html" target="_blank" rel="noopener">goto 语句</a></td>
<td align="left">将控制转移到被标记的语句。但是不建议在程序中使用 goto 语句。</td>
</tr>
</tbody></table>
<h2 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h2><h3 id="调用函数"><a href="#调用函数" class="headerlink" title="调用函数"></a>调用函数</h3><p>创建 C++ 函数时，会定义函数做什么，然后通过调用函数来完成已定义的任务。</p>
<p>当程序调用函数时，程序控制权会转移给被调用的函数。被调用的函数执行已定义的任务，当函数的返回语句被执行时，或到达函数的结束括号时，会把程序控制权交还给主程序。</p>
<p>调用函数时，传递所需参数，如果函数返回一个值，则可以存储返回值。例如：</p>
<h3 id="函数参数"><a href="#函数参数" class="headerlink" title="函数参数"></a>函数参数</h3><p>如果函数要使用参数，则必须声明接受参数值的变量。这些变量称为函数的<strong>形式参数</strong>。</p>
<p>形式参数就像函数内的其他局部变量，在进入函数时被创建，退出函数时被销毁。</p>
<p>当调用函数时，有三种向函数传递参数的方式：</p>
<table>
<thead>
<tr>
<th align="left">调用类型</th>
<th align="left">描述</th>
</tr>
</thead>
<tbody><tr>
<td align="left"><a href="https://www.runoob.com/cplusplus/cpp-function-call-by-value.html" target="_blank" rel="noopener">传值调用</a></td>
<td align="left">该方法把参数的实际值赋值给函数的形式参数。在这种情况下，修改函数内的形式参数对实际参数没有影响。</td>
</tr>
<tr>
<td align="left"><a href="https://www.runoob.com/cplusplus/cpp-function-call-by-pointer.html" target="_blank" rel="noopener">指针调用</a></td>
<td align="left">该方法把参数的地址赋值给形式参数。在函数内，该地址用于访问调用中要用到的实际参数。这意味着，修改形式参数会影响实际参数。</td>
</tr>
<tr>
<td align="left"><a href="https://www.runoob.com/cplusplus/cpp-function-call-by-reference.html" target="_blank" rel="noopener">引用调用</a></td>
<td align="left">该方法把参数的引用赋值给形式参数。在函数内，该引用用于访问调用中要用到的实际参数。这意味着，修改形式参数会影响实际参数。</td>
</tr>
</tbody></table>
<p>默认情况下，C++ 使用传值调用来传递参数。一般来说，这意味着函数内的代码不能改变用于调用函数的参数。之前提到的实例，调用 max() 函数时，使用了相同的方法。</p>
<p>向函数传递参数的<strong>引用调用</strong>方法，把引用的地址复制给形式参数。在函数内，该引用用于访问调用中要用到的实际参数。这意味着，修改形式参数会影响实际参数。</p>
<p>按引用传递值，参数引用被传递给函数，就像传递其他值给函数一样。因此相应地，在下面的函数 <strong>swap()</strong> 中，您需要声明函数参数为引用类型，该函数用于交换参数所指向的两个整数变量的值。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 函数定义</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">swap</span><span class="params">(<span class="keyword">int</span> &amp;x, <span class="keyword">int</span> &amp;y)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">   <span class="keyword">int</span> temp;</span><br><span class="line">   temp = x; <span class="comment">/* 保存地址 x 的值 */</span></span><br><span class="line">   x = y;    <span class="comment">/* 把 y 赋值给 x */</span></span><br><span class="line">   y = temp; <span class="comment">/* 把 x 赋值给 y  */</span></span><br><span class="line">  </span><br><span class="line">   <span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>引用的一个重要作用就是作为函数的参数。以前的C语言中函数参数传递是值传递，如果有大块数据作为参数传递的时候，采用的方案往往是指针，因为 这样可以避免将整块数据全部压栈，可以提高程序的效率。但是现在（C++中）又增加了一种同样有效率的选择（在某些特殊情况下又是必须的选择），就是引 用。</p>
<p>如果既要利用引用提高程序的效率，又要保护传递给函数的数据不在函数中被改变，就应使用常引用。常引用声明方式：const 类型标识符 &amp;引用名=目标变量名；用这种方式声明的引用，不能通过引用对目标变量的值进行修改,从而使引用的目标成为const，达到了引用的安全性。</p>
<p>要以引用返回函数值，则函数定义时要按以下格式：</p>
<p>类型标识符 &amp;函数名（形参列表及类型说明）<br>{函数体}</p>
<p>说明：（1）以引用返回函数值，定义函数时需要在函数名前加&amp;</p>
<p>（2）用引用返回一个函数值的最大好处是，在内存中不产生被返回值的副本。</p>
<h2 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h2><p>多维数组：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//多维数组声明的一般形式如下：</span></span><br><span class="line">type name[size1][size2]...[sizeN];</span><br><span class="line"><span class="comment">//例如，下面的声明创建了一个三维 5 . 10 . 4 整型数组：</span></span><br><span class="line"><span class="keyword">int</span> threedim[<span class="number">5</span>][<span class="number">10</span>][<span class="number">4</span>];</span><br><span class="line"><span class="comment">//多维数组最简单的形式是二维数组。一个二维数组，在本质上，是一个一维数组的列表。声明一个 x 行 y 列的二维整型数组，形式如下：</span></span><br><span class="line"><span class="keyword">int</span> a[<span class="number">3</span>][<span class="number">4</span>] = &#123;  </span><br><span class="line"> &#123;<span class="number">0</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>&#125; ,   <span class="comment">/*  初始化索引号为 0 的行 */</span></span><br><span class="line"> &#123;<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>&#125; ,   <span class="comment">/*  初始化索引号为 1 的行 */</span></span><br><span class="line"> &#123;<span class="number">8</span>, <span class="number">9</span>, <span class="number">10</span>, <span class="number">11</span>&#125;   <span class="comment">/*  初始化索引号为 2 的行 */</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<p>指向数组的指针：runoobAarray 是一个指向 &amp;runoobAarray[0] 的指针，即数组 runoobAarray 的第一个元素的地址。一旦您把第一个元素的地址存储在 p 中，您就可以使用 <em>p、</em>(p+1)、*(p+2) 等来访问数组元素。</p>
<p>C++ 中您可以通过指定不带索引的数组名来传递一个指向数组的指针。C++ 传数组给一个函数，数组类型自动转换为指针类型，因而传的实际是地址。</p>
<p>如果您想要在函数中传递一个一维数组作为参数，您必须以下面三种方式来声明函数形式参数，这三种声明方式的结果是一样的，因为每种方式都会告诉编译器将要接收一个整型指针。同样地，您也可以传递一个多维数组作为形式参数。</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">myFunction</span><span class="params">(<span class="keyword">int</span> *param)</span><span class="comment">//param[10]//param[]</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">.</span><br><span class="line">.</span><br><span class="line">.</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>C++ 不允许返回一个完整的数组作为函数的参数。但是，您可以通过指定不带索引的数组名来返回一个指向数组的指针。</p>
<p>如果您想要从函数返回一个一维数组，您必须声明一个返回指针的函数，如下：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">int</span> * <span class="title">myFunction</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">.</span><br><span class="line">.</span><br><span class="line">.</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//另外，C++ 不支持在函数外返回局部变量的地址，除非定义局部变量为 static 变量。</span></span><br><span class="line"><span class="comment">//现在，让我们来看下面的函数，它会生成 10 个随机数，并使用数组来返回它们，具体如下：</span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;cstdlib&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;ctime&gt;</span></span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 要生成和返回随机数的函数</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> * <span class="title">getRandom</span><span class="params">( )</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">  <span class="keyword">static</span> <span class="keyword">int</span>  r[<span class="number">10</span>];</span><br><span class="line"> </span><br><span class="line">  <span class="comment">// 设置种子</span></span><br><span class="line">  srand( (<span class="keyword">unsigned</span>)time( <span class="literal">NULL</span> ) );</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; ++i)</span><br><span class="line">  &#123;</span><br><span class="line">    r[i] = rand();</span><br><span class="line">    <span class="built_in">cout</span> &lt;&lt; r[i] &lt;&lt; <span class="built_in">endl</span>;</span><br><span class="line">  &#125;</span><br><span class="line"> </span><br><span class="line">  <span class="keyword">return</span> r;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 要调用上面定义函数的主函数</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">   <span class="comment">// 一个指向整数的指针</span></span><br><span class="line">   <span class="keyword">int</span> *p;</span><br><span class="line"> </span><br><span class="line">   p = getRandom();</span><br><span class="line">   <span class="keyword">for</span> ( <span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++ )</span><br><span class="line">   &#123;</span><br><span class="line">       <span class="built_in">cout</span> &lt;&lt; <span class="string">"*(p + "</span> &lt;&lt; i &lt;&lt; <span class="string">") : "</span>;</span><br><span class="line">       <span class="built_in">cout</span> &lt;&lt; *(p + i) &lt;&lt; <span class="built_in">endl</span>;</span><br><span class="line">   &#125;</span><br><span class="line">   <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="引用"><a href="#引用" class="headerlink" title="引用"></a>引用</h2><p>引用很容易与指针混淆，它们之间有三个主要的不同：</p>
<ul>
<li>不存在空引用。引用必须连接到一块合法的内存。</li>
<li>一旦引用被初始化为一个对象，就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。</li>
<li>引用必须在创建时被初始化。指针可以在任何时间被初始化。</li>
</ul>
<p>试想变量名称是变量附属在内存位置中的标签，您可以把引用当成是变量附属在内存位置中的第二个标签。因此，您可以通过原始变量名称或引用来访问变量的内容。例如：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span>&amp;  r = i;</span><br><span class="line"><span class="keyword">double</span>&amp; s = d;</span><br></pre></td></tr></table></figure>

<p>在这些声明中，&amp; 读作<strong>引用</strong>。因此，第一个声明可以读作 “r 是一个初始化为 i 的整型引用”，第二个声明可以读作 “s 是一个初始化为 d 的 double 型引用”。下面的实例使用了 int 和 double 引用：</p>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string">&lt;iostream&gt;</span></span></span><br><span class="line"> </span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">   <span class="comment">// 声明简单的变量</span></span><br><span class="line">   <span class="keyword">int</span>    i;</span><br><span class="line">   <span class="keyword">double</span> d;</span><br><span class="line"> </span><br><span class="line">   <span class="comment">// 声明引用变量</span></span><br><span class="line">   <span class="keyword">int</span>&amp;    r = i;</span><br><span class="line">   <span class="keyword">double</span>&amp; s = d;</span><br><span class="line">   </span><br><span class="line">   i = <span class="number">5</span>;</span><br><span class="line">   <span class="built_in">cout</span> &lt;&lt; <span class="string">"Value of i : "</span> &lt;&lt; i &lt;&lt; <span class="built_in">endl</span>;</span><br><span class="line">   <span class="built_in">cout</span> &lt;&lt; <span class="string">"Value of i reference : "</span> &lt;&lt; r  &lt;&lt; <span class="built_in">endl</span>;</span><br><span class="line"> </span><br><span class="line">   d = <span class="number">11.7</span>;</span><br><span class="line">   <span class="built_in">cout</span> &lt;&lt; <span class="string">"Value of d : "</span> &lt;&lt; d &lt;&lt; <span class="built_in">endl</span>;</span><br><span class="line">   <span class="built_in">cout</span> &lt;&lt; <span class="string">"Value of d reference : "</span> &lt;&lt; s  &lt;&lt; <span class="built_in">endl</span>;</span><br><span class="line">   </span><br><span class="line">   <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">结果如下：</span></span><br><span class="line"><span class="comment">Value of i : 5</span></span><br><span class="line"><span class="comment">Value of i reference : 5</span></span><br><span class="line"><span class="comment">Value of d : 11.7</span></span><br><span class="line"><span class="comment">Value of d reference : 11.7</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure>


    </div>
    
    
    
    
    <div>
      
        <div>
    
        <div style="text-align:center;color: #ccc;font-size:14px;">-------------本文结束<i class="fa fa-paw"></i>感谢您的阅读-------------</div>
    
</div>

      
    </div>
        <div class="reward-container">
  <div>坚持原创技术分享，您的支持将鼓励我继续创作！</div>
  <button onclick="var qr = document.getElementById('qr'); qr.style.display = (qr.style.display === 'none') ? 'block' : 'none';">
    打赏
  </button>
  <div id="qr" style="display: none;">
      
      <div style="display: inline-block;">
        <img src="/images/alipay.png" alt="Li Yudong 支付宝">
        <p>支付宝</p>
      </div>

  </div>
</div>

        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>Li Yudong
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="http://example.com/2020/08/19/C++/C-%E5%9B%9B%E5%A4%A9%E5%85%A5%E9%97%A8/" title="C++初见">http://example.com/2020/08/19/C++/C-四天入门/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="noopener" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>

    
      <footer class="post-footer">
          <div class="post-tags">
              <a href="/tags/C-%E5%88%9D%E5%AD%A6/" rel="tag"># C++初学</a>
          </div>
    
        

    
        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2020/08/15/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E9%A6%96%E7%AF%87%E5%8D%9A%E6%96%87/" rel="prev" title="基于HEXO的博客搭建">
      <i class="fa fa-chevron-left"></i> 基于HEXO的博客搭建
    </a></div>
      <div class="post-nav-item">
    <a href="/2020/08/19/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E5%88%9D%E8%A7%81/" rel="next" title="MXNET机器学习初见">
      MXNET机器学习初见 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#基础架构"><span class="nav-number">1.</span> <span class="nav-text">基础架构</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1、数组与函数的关系"><span class="nav-number">1.1.</span> <span class="nav-text">1、数组与函数的关系</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2、C-的编程逻辑"><span class="nav-number">1.2.</span> <span class="nav-text">2、C++的编程逻辑</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3、程序执行的底层"><span class="nav-number">1.3.</span> <span class="nav-text">3、程序执行的底层</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#C源码—编译—》对象文件—链接—》可执行程序"><span class="nav-number">1.3.1.</span> <span class="nav-text">C源码—编译—》对象文件—链接—》可执行程序</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#h头文件—》放置声明-源文件—》放置定义"><span class="nav-number">1.3.2.</span> <span class="nav-text">.h头文件—》放置声明   源文件—》放置定义</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4、google测试框架"><span class="nav-number">1.4.</span> <span class="nav-text">4、google测试框架</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#添加谷歌测试框架"><span class="nav-number">1.4.1.</span> <span class="nav-text">添加谷歌测试框架</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#使用printf输出彩色信息"><span class="nav-number">1.4.2.</span> <span class="nav-text">使用printf输出彩色信息</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#实现调试信息log日志打印功能"><span class="nav-number">1.4.3.</span> <span class="nav-text">实现调试信息log日志打印功能</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#预处理命令-条件编译"><span class="nav-number">1.4.4.</span> <span class="nav-text">预处理命令-条件编译</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#实现EXCEPT系列封装"><span class="nav-number">1.4.5.</span> <span class="nav-text">实现EXCEPT系列封装</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5、简单算法"><span class="nav-number">1.5.</span> <span class="nav-text">5、简单算法</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#简单版快速排序："><span class="nav-number">1.5.1.</span> <span class="nav-text">简单版快速排序：</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#version1"><span class="nav-number">1.5.1.1.</span> <span class="nav-text">version1</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#version2：单边递归法"><span class="nav-number">1.5.1.2.</span> <span class="nav-text">version2：单边递归法</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#version3：无监督优化"><span class="nav-number">1.5.1.3.</span> <span class="nav-text">version3：无监督优化</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#version4：基准值选择优化"><span class="nav-number">1.5.1.4.</span> <span class="nav-text">version4：基准值选择优化</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#6、虚函数"><span class="nav-number">1.6.</span> <span class="nav-text">6、虚函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#为什么虚函数可以跟着对象走："><span class="nav-number">1.6.1.</span> <span class="nav-text">为什么虚函数可以跟着对象走：</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#this指针"><span class="nav-number">1.6.2.</span> <span class="nav-text">this指针</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#C-基础"><span class="nav-number">2.</span> <span class="nav-text">C++基础</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#基本语法"><span class="nav-number">2.1.</span> <span class="nav-text">基本语法</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#数据类型"><span class="nav-number">2.2.</span> <span class="nav-text">数据类型</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#枚举类型"><span class="nav-number">2.2.1.</span> <span class="nav-text">枚举类型</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#变量类型"><span class="nav-number">2.3.</span> <span class="nav-text">变量类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#变量作用域"><span class="nav-number">2.4.</span> <span class="nav-text">变量作用域</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#字面量"><span class="nav-number">2.5.</span> <span class="nav-text">字面量</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#修饰符类型"><span class="nav-number">2.6.</span> <span class="nav-text">修饰符类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#存储类"><span class="nav-number">2.7.</span> <span class="nav-text">存储类</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#auto-存储类"><span class="nav-number">2.7.1.</span> <span class="nav-text">auto 存储类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#register-存储类"><span class="nav-number">2.7.2.</span> <span class="nav-text">register 存储类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#static-存储类"><span class="nav-number">2.7.3.</span> <span class="nav-text">static 存储类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#extern-存储类"><span class="nav-number">2.7.4.</span> <span class="nav-text">extern 存储类</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#mutable-存储类"><span class="nav-number">2.8.</span> <span class="nav-text">mutable 存储类</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#thread-local-存储类"><span class="nav-number">2.9.</span> <span class="nav-text">thread_local 存储类</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#运算符"><span class="nav-number">2.10.</span> <span class="nav-text">运算符</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#循环"><span class="nav-number">2.11.</span> <span class="nav-text">循环</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#函数"><span class="nav-number">2.12.</span> <span class="nav-text">函数</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#调用函数"><span class="nav-number">2.12.1.</span> <span class="nav-text">调用函数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#函数参数"><span class="nav-number">2.12.2.</span> <span class="nav-text">函数参数</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#数组"><span class="nav-number">2.13.</span> <span class="nav-text">数组</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#引用"><span class="nav-number">2.14.</span> <span class="nav-text">引用</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="Li Yudong"
      src="/images/author.jpg">
  <p class="site-author-name" itemprop="name">Li Yudong</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">95</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">14</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">18</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/tiarmor1" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;tiarmor1" rel="noopener" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="mailto:1157019137@qq.com" title="E-Mail → mailto:1157019137@qq.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
  </div>
  <div class="cc-license motion-element" itemprop="license">
    <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" class="cc-opacity" rel="noopener" target="_blank"><img src="/images/cc-by-nc-sa.svg" alt="Creative Commons"></a>
  </div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 2020 – 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Li Yudong</span>
</div>

        








      </div>
    </footer>
  </div>

  
  
  <script color='0,0,0' opacity='0.5' zIndex='-1' count='150' src="/lib1/canvas-nest/canvas-nest.min.js"></script>
  <script src="/lib1/anime.min.js"></script>
  <script src="/lib1/velocity/velocity.min.js"></script>
  <script src="/lib1/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  




  
<script src="/js/local-search.js"></script>













  

  

  
   <canvas class="fireworks" style="position: fixed;left: 0;top: 0;z-index: 1; pointer-events: none;" ></canvas> 
   <script type="text/javascript" src="//cdn.bootcss.com/animejs/2.2.0/anime.min.js"></script> 
   <script type="text/javascript" src="/js/fireworks.js"></script>
  
</body>
</html>

